
package com.shiku.commons.thread.pool;


import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public abstract class AbstractSynRunnable
        extends BaseRunnable {
    private boolean executed = false;
    public AtomicInteger executeCount = new AtomicInteger();


    public AtomicInteger avoidRepeatExecuteCount = new AtomicInteger();


    public AtomicInteger runCount = new AtomicInteger();


    private static Logger log = LoggerFactory.getLogger(AbstractSynRunnable.class);

    private ReadWriteLock runningLock = new ReentrantReadWriteLock();


    public Executor executor;


    private boolean isCanceled = false;


    protected AbstractSynRunnable(Executor executor) {

        this.executor = executor;

    }


    public void execute() {

        this.executor.execute(this);

    }


    public abstract boolean isNeededExecute();


    public boolean isCanceled() {

        return this.isCanceled;

    }


    @Override
    public void run() {

        Lock writeLock = runningLock().writeLock();


        writeLock.lock();

        try {

            this.runCount.incrementAndGet();


            if (isCanceled()) {

                return;

            }


            this.loopCount.set(0);


            runTask();


        } catch (Throwable e) {

            log.error(e.toString(), e);

        } finally {

            setExecuted(false);

            writeLock.unlock();


            if (isNeededExecute()) {

                execute();

            }

        }

    }


    public abstract void runTask();


    public ReadWriteLock runningLock() {

        return this.runningLock;

    }


    public void setCanceled(boolean isCanceled) {

        this.isCanceled = isCanceled;

    }


    public boolean isExecuted() {

        return this.executed;

    }


    public void setExecuted(boolean executed) {

        this.executed = executed;

    }


    public String logstr() {

        return getClass().getName();

    }

}


